﻿#define _CRT_SECURE_NO_WARNINGS 1

//2.位段

// 2.1声明是位段
//位段的声明和结构是类似的，有两个不同：
//1.位段的成员必须是 int、unsigned int 或signed int 。
//2.位段的成员名后边有一个冒号和一个数字。
//3.位段中的位指的是二进制位

//比如：
struct A
{
	int _a : 2;//占2个二进制位
	int _b : 5; //占5个二进制位
	int _c : 10; //占10个二进制位
	int _d : 30;//占30个二进制位
};
//A就是一个位段类型。

//那位段A的大小是多少？
int main()
{
	printf("%d\n", sizeof(struct A));//结果是8
	return 0;
}

//2.2位段的内存分配 
//1. 位段的成员可以是 int unsigned int signed int 或者是 char （属于整形家族）类型
//2. 位段的空间上是按照需要以4个字节（ int ）或者1个字节（ char ）的方式来开辟的。
//3. 位段涉及很多不确定因素，位段是不跨平台的，注重可移植的程序应该避免使用位段。

//一个例子:vs下验证位段的内存开辟
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	printf("%d\n", sizeof(s));
	return 0;
}

//2.3位段的跨平台问题
//1. int 位段被当成有符号数还是无符号数是不确定的。
//2. 位段中最大位的数目不能确定。（16位机器最大16，32位机器最大32，写成27，在16位机器会出问题。
//3. 位段中的成员在内存中从左向右分配，还是从右向左分配标准尚未定义。
//4. 当一个结构包含两个位段，第二个位段成员比较大，无法容纳于第一个位段剩余的位时，是
//舍弃剩余的位还是利用，这是不确定的。


//总结：
//跟结构相比，位段可以达到同样的效果，但是可以很好的节省空间，但是有跨平台的问题存在

//注：位段只能放在结构体中


//3.枚举

//枚举顾名思义就是一一列举。
//把可能的取值一一列举。
//比如我们现实生活中：
//一周的星期一到星期日是有限的7天，可以一一列举。
//性别有：男、女、保密，也可以一一列举。
//月份有12个月，也可以一一列举

//3.1枚举类型的定义

//例如：
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};
enum Color//颜色
{
	RED,
	GREEN,
	BLUE
};
//以上定义的 enum Day ， enum Sex ， enum Color 都是枚举类型。 { }中的内容是枚举类型的可能取
//值，也叫枚举常量 。
int main()
{
	enum Sex s;//用枚举类型创建变量s
	int age;//跟通过整型类型创建变量是一个效果
	return 0;
}
//这些可能取值都是有值的，默认从0开始，一次递增1，当然在定义的时候也可以赋初值。 例如：
enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};


//3.2枚举的优点

//为什么使用枚举？
//我们可以使用 #define 定义常量，为什么非要使用枚举？ 枚举的优点：
//1. 增加代码的可读性和可维护性
//2. 和#deﬁne定义的标识符比较枚举有类型检查，更加严谨。
//3. 防止了命名污染（封装）
//4. 便于调试
//5. 使用方便，一次可以定义多个常量


//3.3枚举的使用

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
int main()
{
	enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值，才不会出现类型的差异。
	return 0;
}


//4.联合（共用体）

//4.1联合类型的定义

//联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员，特征是这些成员公用同一块
//空间（所以联合也叫共用体）
//比如：

union UN
{
	char c;
	int i;
};

int main()
{
	union UN un;//联合体变量的定义
	printf("%d\n", sizeof(un));//结果是4
	//为什么是4呢？看下面三行代码的结果：
	printf("%p\n", &(un.c));
	printf("%p\n", &(un.i));
	printf("%p\n", &un);//三行代码输出结果一样
	return;
}

//4.2联合体的特点

//联合的成员是共用同一块内存空间的，这样一个联合变量的大小，至少是最大成员的大小（因为
//联合至少得有能力保存最大的那个成员）



//4.3联合大小的计算 (存在一定对齐）

//1.联合的大小至少是最大成员的大小。
//2.当最大成员大小不是最大对齐数的整数倍的时候，就要对齐到最大对齐数的整数倍。
//比如：

union UN1
{
	char c[5];
	int n;
};
union UN2
{
	short c[7];
	int i;
};
int main()
{
	printf("%d\n", sizeof(union UN1));//结果是8
	printf("%d\n", sizeof(union UN2));//结果是16
	return 0;
}


//面试题目：判断当前计算机的大小端存储


int main()
{
	union Un
	{
		char c;
		int i;
	};
	union Un un;
	un.i = 1;
	if (un.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}








